package com.baseproject.datasource.local;

import android.support.annotation.NonNull;

import com.baseproject.BaseApplication;
import com.baseproject.datasource.get.procedure.DataProcedure;
import com.baseproject.datasource.local.database.BaseLocalDatabaseStrategy;
import com.baseproject.datasource.local.database.dao.MyOrmLiteDatabaseStrategy;
import com.baseproject.datasource.local.file.ILocalFileStrategy;
import com.baseproject.datasource.local.file.MyLocalFileStrategy;
import com.baseproject.helper.IBackgroundThreadTask;
import com.baseproject.helper.ThreadHelper;

import org.json.JSONObject;

import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import rx.Observable;

import static com.baseproject.helper.ThreadHelper.defaultSubscriber;

//import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Concrete implementation of a data source as a db.
 */
public class LocalDataSource{

    private static LocalDataSource INSTANCE;

    private static String TAG = "LocalDataSource";

    private BaseLocalDatabaseStrategy baseLocalDatabaseStrategy;

    private ILocalFileStrategy iLocalFileStrategy;

    public static int MAX_SIZE = 10 * 1024 * 1024;


    // Prevent direct instantiation.
    private LocalDataSource() {
        baseLocalDatabaseStrategy = new MyOrmLiteDatabaseStrategy();
        iLocalFileStrategy = new MyLocalFileStrategy();
        try {
            iLocalFileStrategy.init(BaseApplication.getApplication(), MAX_SIZE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static LocalDataSource getInstance() {
        if (INSTANCE == null) {
            synchronized (LocalDataSource.class) {
                if (INSTANCE == null) {
                    INSTANCE = new LocalDataSource();
                }
            }
        }
        return INSTANCE;
    }

    public BaseLocalDatabaseStrategy getBaseLocalDatabaseStrategy() {
        return baseLocalDatabaseStrategy;
    }

    public void setBaseLocalDatabaseStrategy(BaseLocalDatabaseStrategy baseLocalDatabaseStrategy) {
        this.baseLocalDatabaseStrategy = baseLocalDatabaseStrategy;
    }

    public ILocalFileStrategy getiLocalFileStrategy() {
        return iLocalFileStrategy;
    }

    public void setiLocalFileStrategy(ILocalFileStrategy iLocalFileStrategy) {
        this.iLocalFileStrategy = iLocalFileStrategy;
    }


    //对外暴露的方法
    public <T> Observable<List<T>> getList(DataProcedure dataProcedure, Class<T> className) {
        return dataProcedure.getRequestType().getListFromLocal(dataProcedure, className);
    }

    //////////////////////////数据库的增删改查///////////////////////////////////////
    public <T> void insertItem(@NonNull T item) {
        ThreadHelper.doInBackground(new IBackgroundThreadTask() {
            @Override
            public Object backgroundCall() {
                baseLocalDatabaseStrategy.insertItem(item);
                return null;
            }
        })
                .subscribe(defaultSubscriber);
    }

    public <T> void insertItems(@NonNull List<T> items) {
        ThreadHelper.doInBackground(new IBackgroundThreadTask() {
            @Override
            public Object backgroundCall() {
                baseLocalDatabaseStrategy.insertItems(items);
                return null;
            }
        })
                .subscribe(defaultSubscriber);
    }

    public <T> void delete(Class<T> className, Map<String, String> where) {
        ThreadHelper.doInBackground(new IBackgroundThreadTask() {
            @Override
            public Object backgroundCall() {
                baseLocalDatabaseStrategy.delete(className, where);
                return null;
            }
        })
                .subscribe(defaultSubscriber);
    }

    public <T> void updateItem(@NonNull T item, Map<String, String> where) {
        ThreadHelper.doInBackground(new IBackgroundThreadTask() {
            @Override
            public Object backgroundCall() {
                baseLocalDatabaseStrategy.updateItem(item, where);
                return null;
            }
        })
                .subscribe(defaultSubscriber);
    }

    public <T> void updateItems(@NonNull List<T> items, Map<String, String> where) {
        ThreadHelper.doInBackground(new IBackgroundThreadTask() {
            @Override
            public Object backgroundCall() {
                baseLocalDatabaseStrategy.updateItems(items, where);
                return null;
            }
        })
                .subscribe(defaultSubscriber);
    }

    public <T> Observable<List<T>> getList(Class<T> className, Map<String, String> where, String[] projections) {
        return ThreadHelper.doInBackground(new IBackgroundThreadTask() {
            @Override
            public Object backgroundCall() {
                List<T> result = baseLocalDatabaseStrategy.getList(className, where, projections);
                return result;
            }
        });
    }

    //////////////////////////Object的读写///////////////////////////////////////

    public <T> Observable<T> getObjectInternal(String fileName, Class<T> className) {
        return iLocalFileStrategy.getUsingObservable(fileName, className);
    }

    public Observable<Boolean> saveObjectIntoFile(JSONObject jsonObject, String fileName) {
        return iLocalFileStrategy.putUsingObservable(fileName, jsonObject);
    }

    //////////////////////////File的读写///////////////////////////////////////
    public Observable<File> getFile(final String destDir, final String destFileName) {
        return iLocalFileStrategy.getFile(destDir, destFileName);
    }

    public File saveFile(InputStream is, String path, String fileName) {
        return iLocalFileStrategy.saveFile(is, path, fileName);
    }
}
